import get from 'lodash-es/get.js';
import debounce from 'lodash-es/debounce.js';

export default class PolygonLayer {
  constructor(options) {
    const opt = {
      map: null,
      AMap: null,
      label: {
        show: true,
        getText: null,
        getStyle: null,
      },
      polygon: {
        style: {
          bubble: true,
          strokeColor: '#22ddee',
          strokeStyle: 'solid',
          strokeWeight: 5,
          strokeOpacity: 0.8,
          fillColor: '#6CC4CC',
          fillOpacity: 0.6,
        },
        hoverEnable: false,
      },
      replaceFields: {
        bubble: 'bubble',
        /* polygon fields */
        path: 'path',
        strokeColor: 'strokeColor',
        strokeStyle: 'strokeStyle',
        strokeWeight: 'strokeWeight',
        strokeOpacity: 'strokeOpacity',
        fillColor: 'fillColor',
        fillOpacity: 'fillOpacity',
        /* label fields */
        label: 'label',
        labelPosition: 'labelPosition',
      },
      /*
       * polygon事件:
       * onClick(){},
       * onXXXXX(){}...,
       * label事件:
       * onLabelClick(){},
       * onLabelXXXXX(){}...,
       * */
    };
    const merge = (option, opt, keyPath) => {
      return Object.assign({}, get(opt, keyPath), get(options, keyPath));
    };
    this.options = Object.assign({}, opt, options);
    this.options.label = merge(this.options, opt, 'label');
    this.options.polygon = merge(this.options, opt, 'polygon');
    this.options.polygon.style = merge(this.options, opt, 'polygon.style');
    this.options.replaceFields = merge(this.options, opt, 'replaceFields');
    if (this.options.AMap) {
      this.layer = new this.options.AMap.OverlayGroup();
    } else {
      this.layer = new AMap.OverlayGroup();
    }
    this.layer.setMap(this.options.map);
  }
  render(list) {
    if (Array.isArray(list)) {
      this.dataSource = list;
    }
    this.layer.clearOverlays();
    this.layer.addOverlays(this.getPolygons(this.dataSource));
    if (this.options.label.show === true) {
      this.layer.addOverlays(this.getLabels(this.dataSource));
    }
  }
  getLabel(data) {
    let getText = this.options.label.getText;
    let getStyle = this.options.label.getStyle;
    let fields = this.options.replaceFields;
    if (!data || !data[fields.label] || !data[fields.labelPosition]) {
      return;
    }
    let labelText = data[fields.label];
    if (typeof getText === 'function') {
      labelText = getText(data);
    }
    let style = {
      fontsize: '16px',
      fontWeight: 'bolder',
      color: '#fff',
      backgroundColor: 'transparent',
      border: 'none',
    };
    if (typeof getStyle === 'function') {
      style = Object.assign({}, style, getStyle(data));
    }
    const config = {
      text: labelText,
      position: data[fields.labelPosition],
      bubble: data[fields.bubble] || true,
      extData: data,
      style: style,
    };
    const text = this.options.AMap ? new this.options.AMap.Text(config) : new AMap.Text(config);
    Object.keys(this.options).forEach((key) => {
      if (this.isLabelEvent(key) && typeof this.options[key] === 'function') {
        // 不知道为什么，会执行两次点击事件
        text.on(key.replace(/^onLabel/, '').toLocaleLowerCase(), debounce(this.options[key], 150));
      }
    });
    return text;
  }
  getLabels(list) {
    if (!Array.isArray(list)) {
      return [];
    }
    return list.map((item) => this.getLabel(item)).filter(Boolean);
  }
  getPolygonOption(data) {
    const fields = this.options.replaceFields;
    const style = this.options.polygon.style;
    return Object.assign({}, style, {
      path: data[fields.path],
      bubble: typeof data[fields.bubble] === 'boolean' ? data[fields.bubble] : style.bubble,
      strokeColor: data[fields.strokeColor] || style.strokeColor,
      strokeStyle: data[fields.strokeStyle] || style.strokeStyle,
      strokeWeight: data[fields.strokeWeight] || style.strokeWeight,
      strokeOpacity: data[fields.strokeOpacity] || style.strokeOpacity,
      fillColor: data[fields.fillColor] || style.fillColor,
      fillOpacity: data[fields.fillOpacity] || style.fillOpacity,
    });
  }
  getPolygon(data) {
    const fields = this.options.replaceFields;
    if (!data || !data[fields.path] || !data[fields.path].length) {
      return;
    }
    const hoverEnable = this.options.polygon.hoverEnable;
    const options = this.getPolygonOption(data);
    const configData = Object.assign({}, options, {
      extData: data,
      strokeOpacity: options.strokeOpacity * 0.5,
      fillOpacity: options.fillOpacity * 0.5,
    });
    const polygon = this.options.AMap ? new this.options.AMap.Polygon(configData) : new AMap.Polygon(configData);
    if (hoverEnable === true) {
      polygon.on('mouseover', (e) => {
        if (e.target.CLASS_NAME === 'AMap.Polygon') {
          e.target.setOptions({
            strokeOpacity: options.strokeOpacity * 0.9,
            fillOpacity: options.fillOpacity * 0.9,
          });
        }
      });
      polygon.on('mouseout', (e) => {
        if (e.target.CLASS_NAME === 'AMap.Polygon') {
          e.target.setOptions({
            strokeOpacity: options.strokeOpacity * 0.5,
            fillOpacity: options.fillOpacity * 0.5,
          });
        }
      });
    }
    Object.keys(this.options).forEach((key) => {
      if (this.isPolygonEvent(key) && typeof this.options[key] === 'function') {
        // 不知道为什么，会执行两次点击事件
        polygon.on(key.replace(/^on/, '').toLocaleLowerCase(), debounce(this.options[key], 150));
      }
    });
    return polygon;
  }
  getPolygons(list) {
    if (!Array.isArray(list)) {
      return [];
    }
    return list
      .map((item) => this.getPolygon(item))
      .filter(Boolean)
      .sort((p, n) => n.getArea() - p.getArea())
      .map((item, index) => {
        const opt = item.getOptions();
        item.setOptions({ zIndex: (opt.zIndex || 10) + index });
        return item;
      });
  }
  isLabelEvent(eventName) {
    return /^onLabel[A-Z]/.test(eventName);
  }
  isPolygonEvent(eventName) {
    return /^on[A-Z]/.test(eventName) && !this.isLabelEvent(eventName);
  }
}
